package simulation;

import java.awt.Color;
import java.util.ArrayList;

import combat.protocol.data.RemoteList;
import combat.protocol.interfaces.OrderInt;
import combat.protocol.interfaces.ProjectileInt;
import combat.protocol.interfaces.TeamInt;
import combat.protocol.interfaces.UserInt;
import combat.protocol.interfaces.VehicleInt;

import gnu.cajo.utils.extra.TransparentItemProxy;
import gui.components.map.engine.RenderEngine;
import gui.components.map.engine.RenderQueue;
import gui.components.map.engine.RenderQueueType;
import gui.components.map.objects.objBasic;
import gui.components.map.objects.objMissile;
import gui.components.map.objects.objProjectile;
import gui.components.map.objects.objShip;
import gui.components.map.objects.objSubmarine;
import gui.components.map.objects.objTorpedo;

public class Data implements Runnable
{
        // Remote variables
        private static RemoteList remoteTeams                  			= new RemoteList();
        private static RemoteList remoteVehicles               			= new RemoteList();
        private static RemoteList remoteProjectiles						= new RemoteList();
        
        // Local variables
        private static ArrayList<TeamInt> localTeams					= new ArrayList<TeamInt>();
        private static ArrayList<VehicleInt> localVehicles				= new ArrayList<VehicleInt>();
        
        private static ArrayList<VehicleInt> localFriendlyVehicles		= new ArrayList<VehicleInt>();
        private static ArrayList<VehicleInt> localHostileVehicles		= new ArrayList<VehicleInt>();
        private static ArrayList<VehicleInt> localConvoyVehicles		= new ArrayList<VehicleInt>();
        
        private static  ArrayList<ProjectileInt> localProjectiles 			= new  ArrayList<ProjectileInt>();
        private static ArrayList<ProjectileInt> localFriendlyProjectiles	= new ArrayList<ProjectileInt>();
        private static ArrayList<ProjectileInt> localHostileProjectiles		= new ArrayList<ProjectileInt>();
        
        private static RenderEngine RenderEngine;
        private static Thread Runner;
        
        public Data(RenderEngine _renderengine)
        {
        		RenderEngine = _renderengine;
        		
        		// Create thread and start and stop the thread
        		Runner = new Thread(this,"Data Thread");
        		Runner.start();
        		Runner.stop();
        }
        
        // Function called by the thread
        public void run() 
        {
        	while(true){
        		// Call functions
        		Update();
        		ParseToRenderEngine();       		
        	}
    	}
        
        /******************************** Local get / setters *************************/
        // Gets all remote teams and sets it locally
        private synchronized static boolean setAllTeamsLocal()
        {
        	boolean status = false;
        	localTeams.clear();
        	
            try
            {
            	remoteTeams = Connection.simulation.getTeams_Remote();
            	
	            if(remoteTeams != null)
	            {
	                for(Object teamRemote : remoteTeams) 
	                {
	                	localTeams.add(((TeamInt)TransparentItemProxy.getItem(teamRemote, new Class[] { TeamInt.class })));    
	                }
	                if(localTeams != null)
	                	status = true;
	            }
            } catch (Exception e) {
				status = false;
			}
			return status;
        }
        
        // Gets all remote vehicles and sets it locally
        private synchronized static boolean setAllVehiclesLocal()
        {       
        	boolean status = false;
        	localVehicles.clear();
        	
            for(int i = 0; i < localTeams.size(); i++)
            {
            	try
            	{
	            	remoteVehicles = localTeams.get(i).getVehicles_Remote();
	            	
	            	if(remoteVehicles != null)
	                {
	                    for(Object vehRemote : remoteVehicles) 
	                    {
	                    	localVehicles.add((VehicleInt)TransparentItemProxy.getItem(vehRemote, new Class[] { VehicleInt.class }));  
	                    }
	                    if(localVehicles != null)
	                    	status = true;
	                }
            	} catch (Exception e) {
					status = false;
				}
            }
			return status;
        }
        
        // Gets all remote vehicles and splits it into friendly / hostile vehicles and sets this locally
        private synchronized static boolean setStandingVehiclesLocal()
        {
        	boolean status = false;
        	localFriendlyVehicles.clear();
        	localHostileVehicles.clear();
        	localConvoyVehicles.clear();
        	
        	try {        		
        		localFriendlyVehicles = getVehiclesByTeam(Connection.getMyTeam());	
        		
        		
        		if(Connection.getMyTeam().getTeamName().equals("Attackers"))
    				localHostileVehicles = getVehiclesByTeam(localTeams.get(0));
        		
        		if(Connection.getMyTeam().getTeamName().equals("Defenders"))
        		{
        			localHostileVehicles = getVehiclesByTeam(localTeams.get(1));
        			localConvoyVehicles = getVehiclesByTeam(localTeams.get(3));
        		}
        		
        		if(Connection.getMyTeam().getTeamName().equals("Spectators"))
        		{
    				localFriendlyVehicles = localVehicles;
    				localHostileVehicles = null;
        		}
        		status = true;
        	}
        	catch  (Exception e) {
        		status = false;
        	}
        	
        	return status;
        } 
        
     // Gets all remote projectiles and sets it locally
        private synchronized static boolean setAllProjectilesLocal()
        {
        	boolean status = false;
        	localProjectiles.clear();
        	
            for(int i = 0; i < localProjectiles.size(); i++)
            {
            	try
            	{
            		remoteProjectiles = localTeams.get(i).getProjectiles_Remote();
	            	
	            	if(remoteProjectiles != null)
	                {
	                    for(Object projRemote : remoteProjectiles) 
	                    {
	                    	localProjectiles.add((ProjectileInt)TransparentItemProxy.getItem(projRemote, new Class[] { ProjectileInt.class }));  
	                    }
	                    if(localProjectiles != null)
	                    	status = true;
	                }
            	} catch (Exception e) {
					status = false;
				}
            }
			return status;
        }
        
        /******************************** Getters *************************/        
        public synchronized static ArrayList<TeamInt> getAllTeams()
        {
                return Data.localTeams;
        }
        
        public synchronized static ArrayList<VehicleInt> getAllVehicles()
        {
                return Data.localVehicles;
        }
        
        public synchronized static ArrayList<ProjectileInt> getAllProjectiles()
        {
        	return Data.localProjectiles;
        }
        
        // Gets all vehicles that are of the given team in a ArrayList
        public static ArrayList<VehicleInt> getVehiclesByTeam(TeamInt team)
        {
            ArrayList<VehicleInt> tempVehicles = new ArrayList<VehicleInt>();
            
            for(int i = 0; i < localTeams.size(); i++)
            {
                if(team.getTeamName().equals(localTeams.get(i).getTeamName()))
                {
                	for(int j = 0; j < localTeams.get(i).getVehicles_Remote().size(); j++)
                	{
	                	tempVehicles.add(((VehicleInt)TransparentItemProxy.getItem(localTeams.get(i).getVehicles_Remote().get(j), new Class[] { VehicleInt.class })));  
                	}
                }
            }
            return tempVehicles;
        }
        
        // Gets the vehicle of a specific user
        public static VehicleInt getVehiclePerUser(UserInt user)
        {
        	VehicleInt vehicle = null;
        	try
			{
        		vehicle = (VehicleInt) user.getUserVehicle_Remote();
			} catch (Exception e) {
				System.out.println("ERROR: Could not get the orders");
			}
        	return vehicle;
        }

        // Gets orders per vehicle from a user
        public static ArrayList<OrderInt> getVehicleOrders(UserInt user)
        {
        	ArrayList<OrderInt> tempOrders = new ArrayList<OrderInt>();

        	for(int j = 0; j < Connection.getMyVehicle().getOrders_Remote().size(); j++)
        	{
        		tempOrders.add(((OrderInt)TransparentItemProxy.getItem(Connection.getMyVehicle().getOrders_Remote().get(j), new Class[] { OrderInt.class }))); 
        	}
            return tempOrders;
        }

        // Gets projectiles per team
        public static ArrayList<ProjectileInt> getProjectileByTeam(TeamInt team)
        {
            ArrayList<ProjectileInt> tempProjectiles = new ArrayList<ProjectileInt>();
            
            for(int i = 0; i < localProjectiles.size(); i++)
            {
            	if(team.getTeamName().equals(localTeams.get(i).getTeamName()))
                {
                	for(int j = 0; j < localTeams.get(i).getProjectiles_Remote().size(); j++)
                	{
                		tempProjectiles.add(((ProjectileInt)TransparentItemProxy.getItem(localTeams.get(i).getProjectiles_Remote().get(j), new Class[] { ProjectileInt.class })));  
                	}
                }
            }
            return tempProjectiles;
        }

        /************************** Link met RenderEngine *************************/  
        // Update function that calls all other functions
        public static void Update()
        {
        	setAllTeamsLocal();
        	setAllVehiclesLocal();	
        	setAllProjectilesLocal();
            setStandingVehiclesLocal();
        }
        
        // Parses everything to draw into a queue
        public void ParseToRenderEngine()
        {
        	RenderQueue _vehiclequeue = new RenderQueue();
        	_vehiclequeue.SetType(RenderQueueType.VEHICLE);
        	_vehiclequeue.Add(GenerateFriendlyVehicleQueue());
        	_vehiclequeue.Add(GenerateHostileVehicleQueue());
        	_vehiclequeue.Add(GenerateConvoyVehicleQueue());
        	
        	RenderQueue _projectilequeue = new RenderQueue();
        	_projectilequeue.SetType(RenderQueueType.PROJECTILE);
        	_projectilequeue.Add(GenerateFriendlyProjectileQueue());
        	
        	RenderEngine.RemoveRenderQueue(RenderQueueType.VEHICLE);
        	RenderEngine.RemoveRenderQueue(RenderQueueType.PROJECTILE);
        	RenderEngine.AddRenderQueue(_vehiclequeue);
        	RenderEngine.AddRenderQueue(_projectilequeue);
        }
        
        // Generates all friendly vehicles
        private RenderQueue GenerateFriendlyVehicleQueue()
        {
        	// Create new queue
        	RenderQueue _friendlyvehiclequeue = new RenderQueue();
        	_friendlyvehiclequeue.SetType(RenderQueueType.VEHICLE);      	
        	
        	// Create new object and initialize with null
        	objBasic _object = null;
        	
        	// Add vehicles to queue
    		for(int i = 0; i < localFriendlyVehicles.size(); i++)
    		{			    			
    			// Check vehicle type
    			switch(localFriendlyVehicles.get(i).getVehicleType())
    			{
	    			case FRIGATE:
	    				_object = new objShip();
	    				break;
	    				
	    			case SUBMARINE:
	    				_object = new objSubmarine();
	    				break;
    			}
    			
    			// Sets a specific vehicle to focus for radial grid
    			if(Connection.getMyVehicle().getName().equals(localFriendlyVehicles.get(i).getName()))
    			{
    				_object.IsPlayer();
    			}	
    			
    			Color color = null;
    			if(localFriendlyVehicles.get(i).getHealth() == 0){
    				color = Color.gray; // Sets gray color when vehicle health is 0
    			} else {
    				color = Color.blue; // Sets friendly vehicle color to blue when vehicle health > 0
    			}
    			
    			// Sets colors and text per object
    			_object.SetForegroundColor(color); 
    			_object.HasLabel();
    			_object.setName(localFriendlyVehicles.get(i).getName());
    			_object.SetHealth(localFriendlyVehicles.get(i).getHealth());
    			_object.setPosition(localFriendlyVehicles.get(i).getPosition());
    			_object.setAltitude(localFriendlyVehicles.get(i).getAltitude());
    			_object.setDirection(localFriendlyVehicles.get(i).getDirection());
    			_object.setSpeed(localFriendlyVehicles.get(i).getSpeed());
    			_object.setType(localFriendlyVehicles.get(i).getType());
    			_object.GenerateShape();

    			// Add object to queue
    			_friendlyvehiclequeue.Add(_object);
			}
    		return _friendlyvehiclequeue;   
        }
           
        // Generates all convoy vehicles
        private RenderQueue GenerateConvoyVehicleQueue()
        {
        	// Create new queue
        	RenderQueue _convoyvehiclequeue = new RenderQueue();
        	_convoyvehiclequeue.SetType(RenderQueueType.VEHICLE);      	
        	
        	// Create new object and initialize with null
        	objBasic _object = null;
        	
        	// Add vehicles to queue
    		for(int i = 0; i < localConvoyVehicles.size(); i++)
    		{			   			
    			// Check vehicle type
    			switch(localConvoyVehicles.get(i).getVehicleType())
    			{
	    			case CONVOY:
	    				_object = new objShip();;
	    				break;	
    			}		

    			Color color = null;
    			if(localConvoyVehicles.get(i).getHealth() == 0){
    				color = Color.gray; // Sets gray color when vehicle health is 0
    			} else {
    				color = Color.yellow; // Sets friendly vehicle color to yellow when vehicle health > 0
    			}
    			
    			// Sets colors and text per object
    			_object.SetForegroundColor(color);
    			_object.HasLabel();
    			_object.setName(localConvoyVehicles.get(i).getName());
    			_object.setPosition(localConvoyVehicles.get(i).getPosition());
    			_object.setAltitude(localConvoyVehicles.get(i).getAltitude());
    			_object.setDirection(localConvoyVehicles.get(i).getDirection());
    			_object.setSpeed(localConvoyVehicles.get(i).getSpeed());
    			_object.setType(localConvoyVehicles.get(i).getType());
    			_object.GenerateShape();

    			// Add object to queue
    			_convoyvehiclequeue.Add(_object);
			}
    		return _convoyvehiclequeue; 	
        }
        
        private RenderQueue GenerateHostileVehicleQueue()
        {
        	// Create new queue
	    	RenderQueue _hostilevehiclequeue = new RenderQueue();
	    	_hostilevehiclequeue.SetType(RenderQueueType.VEHICLE);      	
	    	
	    	// Create new object and initialize with null
	    	objBasic _object = null;
	    	
	    	// Add vehicles to queue
			for(int i = 0; i < localHostileVehicles.size(); i++)
			{			   			
				// Check vehicle type
				switch(localHostileVehicles.get(i).getVehicleType())
				{
	    			case FRIGATE:
	    				_object = new objShip();
	    				break;
	    				
	    			case SUBMARINE:
	    				_object = new objSubmarine();
	    				break;
				}		
				
				Color color = null;
				if(localHostileVehicles.get(i).getHealth() == 0){
					color = Color.gray; // Sets gray color when vehicle health is 0
				} else {
					color = Color.red; // Sets friendly vehicle color to red when vehicle health > 0
				}
				
				// Sets colors and text per object
				_object.SetForegroundColor(color);
				_object.HasLabel();
				_object.setName(localHostileVehicles.get(i).getName());
				_object.setPosition(localHostileVehicles.get(i).getPosition());
				_object.setAltitude(localHostileVehicles.get(i).getAltitude());
				_object.setDirection(localHostileVehicles.get(i).getDirection());
				_object.setSpeed(localHostileVehicles.get(i).getSpeed());
				_object.setType(localHostileVehicles.get(i).getType());
				_object.GenerateShape();
	
				// Add object to queue
				_hostilevehiclequeue.Add(_object);
			}
	    	return _hostilevehiclequeue; 	
        }

        
        private RenderQueue GenerateFriendlyProjectileQueue()
        {
        	// Create new queue
        	RenderQueue _friendlyprojectilequeue = new RenderQueue();
        	_friendlyprojectilequeue.SetType(RenderQueueType.PROJECTILE);      	
        	
        	// Create new object and initialize with null
        	objProjectile _object = null;
        	
        	// Add projectiles to queue
    		for(int i = 0; i < localFriendlyProjectiles.size(); i++)
    		{			   			
    			// Check projectile type
    			switch(localFriendlyProjectiles.get(i).getProjectileType())
    			{
	    			case MISSILE_GUIDED:
	    				_object = new objMissile();
	    				break;
	    				
	    			case MISSILE_UNGUIDED:
	    				_object = new objMissile();
	    				break;
	    				
	    			case TORPEDO:
	    				_object = new objTorpedo();
	    				break;	
    			}		
    			
    			// Sets colors and text per projectile
    			_object.SetForegroundColor(Color.pink);
    			_object.HasLabel();
    			_object.setName(localFriendlyProjectiles.get(i).getName());
    			_object.setPosition(localFriendlyProjectiles.get(i).getPosition());
    			_object.setAltitude(localFriendlyProjectiles.get(i).getAltitude());
    			_object.setDirection(localFriendlyProjectiles.get(i).getDirection());
    			_object.setSpeed(localFriendlyProjectiles.get(i).getSpeed());
    			_object.setType(localFriendlyProjectiles.get(i).getType());
    			_object.GenerateShape();
    			
    			// Add projectiles to queue
    			_friendlyprojectilequeue.Add(_object);
			}
    		return _friendlyprojectilequeue; 	
        }
        
        private RenderQueue GenerateHostileProjectileQueue()
        {
        	// Create new queue
        	RenderQueue _hostileprojectilequeue = new RenderQueue();
        	_hostileprojectilequeue.SetType(RenderQueueType.PROJECTILE);      	
        	
        	// Create new object and initialize with null
        	objProjectile _object = null;
        	
        	// Add projectiles to queue
    		for(int i = 0; i < localHostileProjectiles.size(); i++)
    		{			   			
    			// Check projectile type
    			switch(localHostileProjectiles.get(i).getProjectileType())
    			{
	    			case MISSILE_GUIDED:
	    				_object = new objMissile();
	    				break;
	    				
	    			case MISSILE_UNGUIDED:
	    				_object = new objMissile();
	    				break;
	    				
	    			case TORPEDO:
	    				_object = new objTorpedo();
	    				break;	
    			}		
    			
    			// Sets colors and text per projectile
    			_object.SetForegroundColor(Color.orange);
    			_object.HasLabel();
    			_object.setName(localHostileProjectiles.get(i).getName());
    			_object.setPosition(localHostileProjectiles.get(i).getPosition());
    			_object.setAltitude(localHostileProjectiles.get(i).getAltitude());
    			_object.setDirection(localHostileProjectiles.get(i).getDirection());
    			_object.setSpeed(localHostileProjectiles.get(i).getSpeed());
    			_object.setType(localHostileProjectiles.get(i).getType());
    			_object.GenerateShape();

    			// Add projectiles to queue
    			_hostileprojectilequeue.Add(_object);
			}
    		return _hostileprojectilequeue;
        }
        
        // Sets the render engine
        public void SetRenderEngine(RenderEngine _renderengine)
        {	
        	RenderEngine = _renderengine;	
        }
}